<script lang="ts">
    import { onDestroy, onMount, untrack } from "svelte";
    import type { CropperProps } from "./Cropper";
    import CropperFoundation, { type CropperAdapter } from "./Foundation";
    import { useClassList } from "../utils/useClassList";
    import { useStyle } from "../utils/useStyle";

    const props: CropperProps = $props();
    const shape = $derived(props.shape ?? "rect");
    const defaultAspectRatio = props.defaultAspectRatio ?? 1;
    const showResizeBox = props.showResizeBox ?? true;
    const fill = props.fill ?? "rgba(0, 0, 0, 0)";
    const maxZoom = props.maxZoom ?? 3;
    const minZoom = props.minZoom ?? 0.1;
    const zoomStep = props.zoomStep ?? 0.1;

    const options = $derived(
        Object.assign(
            {
                shape,
                defaultAspectRatio,
                showResizeBox,
                fill,
                maxZoom,
                minZoom,
                zoomStep,
            },
            { ...props }
        )
    );

    const corners = {
        shape: ["rect", "round", "roundRect"],
        corner: ["tl", "tm", "tr", "ml", "mr", "bl", "bm", "br"],
        roundCorner: ["tm", "ml", "mr", "bm"],
    };

    // 响应式状态管理
    const store = $state({
        imgData: { width: 0, height: 0, centerPoint: { x: 0, y: 0 } },
        cropperBox: { width: 0, height: 0, centerPoint: { x: 0, y: 0 } },
        loaded: false,
        rotate: 0,
        zoom: props.zoom || 1,
    });

    let containerRef: HTMLDivElement;
    let imgRef: any;

    // 适配器实现
    const adapter: CropperAdapter = {
        getContainer: () => containerRef,
        notifyZoomChange: (zoom) => props.onzoomchange?.(zoom),
        getImg: () => imgRef,
        getState: () => store,
        getProps: () => options,
        setState: (newState) => {
            Object.assign(store, newState);
        },
    };

    // 初始化基础模块
    const foundation: CropperFoundation = new CropperFoundation(adapter);

    // 生命周期处理
    onMount(() => foundation.init());
    onDestroy(() => {
        foundation.destroy();
        containerRef?.removeEventListener("wheel", foundation.handleWheel);
    });

    onMount(() => {
        const ob = new ResizeObserver(() => {
            foundation.handleResize();
        });
        ob.observe(containerRef);

        onDestroy(() => {
            ob.disconnect();
        });
    });

    // 响应式更新处理
    $effect(() => {
        const { rotate, zoom } = props;
        untrack(() => {
            const currentState = store;
            if (!currentState.loaded) return;

            let nextWidth = currentState.imgData.width;
            let nextHeight = currentState.imgData.height;
            let nextImgCenter = { ...currentState.imgData.centerPoint };

            // 旋转处理逻辑
            if (typeof rotate === "number") {
                const cropperBox = currentState.cropperBox;
                const rotateCenter = {
                    x: cropperBox.centerPoint.x,
                    y: -cropperBox.centerPoint.y,
                };
                const imgCenter = {
                    x: currentState.imgData.centerPoint.x,
                    y: -currentState.imgData.centerPoint.y,
                };
                const angle = ((rotate - currentState.rotate) * Math.PI) / 180;
                nextImgCenter = {
                    x: (imgCenter.x - rotateCenter.x) * Math.cos(angle) + (imgCenter.y - rotateCenter.y) * Math.sin(angle) + rotateCenter.x,
                    y: -(-(imgCenter.x - rotateCenter.x) * Math.sin(angle) + (imgCenter.y - rotateCenter.y) * Math.cos(angle) + rotateCenter.y),
                };
                store.rotate = rotate;
            }

            // 缩放处理逻辑
            if (typeof zoom === "number") {
                if (currentState.loaded) {
                    const cropperBox = currentState.cropperBox;
                    // 同上
                    const scaleCenter = {
                        x: cropperBox.centerPoint.x,
                        y: -cropperBox.centerPoint.y,
                    };
                    const currentImgCenter = {
                        x: nextImgCenter.x,
                        y: -nextImgCenter.y,
                    };
                    nextWidth = (currentState.imgData.width / currentState.zoom) * zoom;
                    nextHeight = (currentState.imgData.height / currentState.zoom) * zoom;
                    nextImgCenter = {
                        x: ((currentImgCenter.x - scaleCenter.x) / currentState.zoom) * zoom + scaleCenter.x,
                        y: -[((currentImgCenter.y - scaleCenter.y) / currentState.zoom) * zoom + scaleCenter.y],
                    };
                    store.zoom = zoom;
                }
            }

            store.imgData = { ...store.imgData, width: nextWidth, height: nextHeight, centerPoint: nextImgCenter };
        });
    });

    // 事件处理
    const handleRef = (ref: HTMLDivElement) => {
        containerRef?.removeEventListener("wheel", foundation.handleWheel);
        containerRef = ref;
        ref?.addEventListener("wheel", foundation.handleWheel, { passive: false });
    };

    const classList = $derived(useClassList(props, "cm-cropper"));

    const boxClassList = $derived({
        "cm-cropper-box": true,
        "cm-cropper-box-round": shape === "round",
    });

    export const getCropperCanvas = foundation.getCropperCanvas;

    const imgWidth = $derived(store.imgData.width + "px");
    const imgHeight = $derived(store.imgData.height + "px");

    const imgX = $derived(store.imgData.centerPoint.x - store.imgData.width / 2);
    const imgY = $derived(store.imgData.centerPoint.y - store.imgData.height / 2);

    const cropperBoxX = $derived(store.cropperBox.centerPoint.x - store.cropperBox.width / 2);
    const cropperBoxY = $derived(store.cropperBox.centerPoint.y - store.cropperBox.height / 2);
    const boxWidth = $derived(store.cropperBox.width + "px");
    const boxHeight = $derived(store.cropperBox.height + "px");

    const cropperImgX = $derived(imgX - cropperBoxX);
    const cropperImgY = $derived(imgY - cropperBoxY);
</script>

<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class={classList} style={props.style} use:handleRef>
    <div class="cm-cropper-img-wrap">
        <!-- svelte-ignore a11y_missing_attribute -->
        <img
            bind:this={imgRef}
            src={props.src}
            onload={foundation.handleImageLoad}
            class="cm-cropper-img"
            crossOrigin="anonymous"
            style={`
                    width: ${imgWidth};
                    height: ${imgHeight};
                    transform-origin: center;
                    transform: translate(${imgX}px, ${imgY}px) rotate(${store.rotate || 0}deg);
                `}
        />
    </div>

    <!-- 遮罩层 -->
    <!-- svelte-ignore element_invalid_self_closing_tag -->
    <div class="cm-cropper-mask" onmousedown={foundation.handleMaskMouseDown} />

    <!-- 裁剪框 -->
    <div
        class={boxClassList}
        style={useStyle(
            { style: props.cropperBoxStyle },
            {
                width: boxWidth,
                height: boxHeight,
                transform: `translate(${cropperBoxX}px, ${cropperBoxY}px)`,
            }
        )}
        onmousedown={foundation.handleCropperBoxMouseDown}
    >
        <div
            class={{
                "cm-cropper-view-box": true,
                "cm-cropper-view-box-round": shape?.includes("round"),
            }}
        >
            <!-- svelte-ignore a11y_missing_attribute -->
            <img
                ondragstart={foundation.viewIMGDragStart}
                class="cm-cropper-img"
                src={props.src}
                style={`
                        width: ${imgWidth};
                        height: ${imgHeight};
                        transform-origin: center;
                        transform: translate(${cropperImgX}px, ${cropperImgY}px) rotate(${store.rotate || 0}deg);
                    `}
            />
        </div>
        {#if store.loaded && showResizeBox}
            {#each corners[shape === "round" ? "roundCorner" : "corner"] as string[] as corner}
                <!-- svelte-ignore element_invalid_self_closing_tag -->
                <div
                    class={{
                        "cm-cropper-box-corner": true,
                        [`cm-cropper-box-corner-${corner}`]: true,
                    }}
                    data-dir={corner}
                    onmousedown={foundation.handleCornerMouseDown}
                />
            {/each}
        {/if}
    </div>
</div>
